﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using SHomeWorkshop.LunarPresentation.Expressions;

namespace SHomeWorkshop.LunarPresentation.Widegets
{
    public class BracePanel : Canvas
    {
        public BracePanel(Brace parentBraceExpression)
        {
            this.parentBraceExpression = parentBraceExpression;
            this.Background = Brushes.Transparent;
            this.SizeChanged += new SizeChangedEventHandler(BracePanel_SizeChanged);
        }

        private Brace parentBraceExpression;

        public Brace ParentBraceExpression
        {
            get { return parentBraceExpression; }
            set { parentBraceExpression = value; }
        }

        private Path myPath;

        void BracePanel_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            UpdateBrace();
        }

        private Brush foreground = Brushes.White;//默认白色。

        public Brush Foreground
        {
            get { return foreground; }
            set
            {
                foreground = value;
                UpdateBrace();
            }
        }

        public void UpdateBrace()
        {
            this.Children.Clear();
            if (parentBraceExpression == null) return;
            if (parentBraceExpression.ParentPanel == null) return;

            double halfOfWidth = this.ActualWidth / 2;
            double halfOfHeight = this.ActualHeight / 2;

            if (halfOfHeight <= 0 || halfOfWidth <= 0) return;

            double quarterOfWidth = halfOfWidth / 2;
            double quarterOfHeight = halfOfHeight / 2;

            myPath = new Path();
            myPath.MouseDown += new System.Windows.Input.MouseButtonEventHandler(myPath_MouseDown);
            myPath.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(myPath_MouseLeftButtonUp);
            myPath.Stroke = foreground;
            myPath.StrokeThickness = 2;
            myPath.StrokeLineJoin = PenLineJoin.Round;
            myPath.Fill = foreground;
            RenderOptions.SetClearTypeHint(myPath, ClearTypeHint.Enabled);

            StreamGeometry geometry = new StreamGeometry();
            //geometry.FillRule = FillRule.EvenOdd;

            DrawBrace(geometry, halfOfWidth, halfOfHeight, quarterOfWidth, quarterOfHeight);

            geometry.Freeze();
            myPath.Data = geometry;

            this.Children.Add(myPath);
        }

        void myPath_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.OnMouseLeftButtonUp(e);
        }

        private void DrawBrace(StreamGeometry geometry, double halfOfWidth, double halfOfHeight,
            double quarterOfWidth, double quarterOfHeight)
        {
            if (parentBraceExpression == null || parentBraceExpression.ParentPanel == null) return;

            switch (parentBraceExpression.Braces)
            {
                case Brace.BraceLocation.End:
                    {
                        switch (parentBraceExpression.ParentPanel.Direction)
                        {
                            case Orientation.Vertical:
                                {
                                    DrawBottomBrace(geometry, halfOfWidth, halfOfHeight, quarterOfHeight);
                                    break;
                                }
                            case Orientation.Horizontal:
                                {
                                    DrawRightBrace(geometry, halfOfWidth, halfOfHeight, quarterOfWidth);
                                    break;
                                }
                        }

                        break;
                    }
                default:
                    {
                        switch (parentBraceExpression.ParentPanel.Direction)
                        {
                            case Orientation.Vertical:
                                {
                                    DrawTopBrace(geometry, halfOfWidth, halfOfHeight, quarterOfHeight);
                                    break;
                                }
                            case Orientation.Horizontal:
                                {
                                    DrawLeftBrace(geometry, halfOfWidth, halfOfHeight, quarterOfWidth);
                                    break;
                                }
                        }

                        break;
                    }
            }
        }

        void myPath_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.OnMouseDown(e);
        }

        private void DrawLeftBrace(StreamGeometry geometry, double halfOfWidth, double halfOfHeight, double quarterOfWidth)
        {
            Point apt = new Point(quarterOfWidth * 3, quarterOfWidth);
            Point bpt = new Point(halfOfWidth, quarterOfWidth);
            Point cpt = new Point(halfOfWidth, halfOfWidth /*+ quarterOfWidth*/);
            Point dpt = new Point(halfOfWidth, halfOfHeight - quarterOfWidth/* * 2*/);

            Point ept = new Point(halfOfWidth, halfOfHeight);
            Point fpt = new Point(quarterOfWidth, halfOfHeight);
            Point gpt = new Point(halfOfWidth, halfOfHeight + quarterOfWidth/* * 2*/);
            Point hpt = new Point(halfOfWidth, this.ActualHeight - halfOfWidth /*- quarterOfWidth*/);

            Point ipt = new Point(halfOfWidth, this.ActualHeight - quarterOfWidth);
            Point jpt = new Point(quarterOfWidth * 3, this.ActualHeight - quarterOfWidth);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                ctx.BeginFigure(apt, false /* is filled */, false /* is closed */);

                if (cpt.Y > dpt.Y || gpt.Y > hpt.Y)
                {
                    Point newB = new Point(bpt.X - quarterOfWidth, bpt.Y);
                    Point newE = new Point(ept.X + quarterOfWidth, ept.Y);
                    Point newI = new Point(ipt.X - quarterOfWidth, ipt.Y);
                    ctx.BezierTo(newB, newE, fpt, true, true);
                    ctx.BezierTo(newE, newI, jpt, true, true);
                }
                else
                {
                    ctx.QuadraticBezierTo(bpt, cpt, true, true);
                    ctx.LineTo(dpt, true, true);
                    ctx.QuadraticBezierTo(ept, fpt, true, true);
                    ctx.QuadraticBezierTo(ept, gpt, true, true);
                    ctx.LineTo(hpt, true, true);
                    ctx.QuadraticBezierTo(ipt, jpt, true, true);
                }
            }
        }

        private void DrawRightBrace(StreamGeometry geometry, double halfOfWidth, double halfOfHeight, double quarterOfWidth)
        {
            Point apt = new Point(quarterOfWidth, quarterOfWidth);
            Point bpt = new Point(halfOfWidth, quarterOfWidth);
            Point cpt = new Point(halfOfWidth, halfOfWidth /*+ quarterOfWidth*/);
            Point dpt = new Point(halfOfWidth, halfOfHeight - quarterOfWidth/* * 2*/);

            Point ept = new Point(halfOfWidth, halfOfHeight);
            Point fpt = new Point(quarterOfWidth * 3, halfOfHeight);
            Point gpt = new Point(halfOfWidth, halfOfHeight + quarterOfWidth/* * 2*/);
            Point hpt = new Point(halfOfWidth, this.ActualHeight - halfOfWidth /*- quarterOfWidth*/);

            Point ipt = new Point(halfOfWidth, this.ActualHeight - quarterOfWidth);
            Point jpt = new Point(quarterOfWidth, this.ActualHeight - quarterOfWidth);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                ctx.BeginFigure(apt, false /* is filled */, false /* is closed */);

                if (cpt.Y > dpt.Y || gpt.Y > hpt.Y)
                {
                    Point newB = new Point(bpt.X + quarterOfWidth, bpt.Y);
                    Point newE = new Point(ept.X - quarterOfWidth, ept.Y);
                    Point newI = new Point(ipt.X + quarterOfWidth, ipt.Y);
                    ctx.BezierTo(newB, newE, fpt, true, true);
                    ctx.BezierTo(newE, newI, jpt, true, true);
                }
                else
                {
                    ctx.QuadraticBezierTo(bpt, cpt, true, true);
                    ctx.LineTo(dpt, true, true);
                    ctx.QuadraticBezierTo(ept, fpt, true, true);
                    ctx.QuadraticBezierTo(ept, gpt, true, true);
                    ctx.LineTo(hpt, true, true);
                    ctx.QuadraticBezierTo(ipt, jpt, true, true);
                }
            }
        }

        private void DrawTopBrace(StreamGeometry geometry, double halfOfWidth, double halfOfHeight, double quarterOfHeight)
        {
            Point apt = new Point(quarterOfHeight, quarterOfHeight * 3);
            Point bpt = new Point(quarterOfHeight, halfOfHeight);
            Point cpt = new Point(halfOfHeight, halfOfHeight);
            Point dpt = new Point(halfOfWidth - quarterOfHeight, halfOfHeight);

            Point ept = new Point(halfOfWidth, halfOfHeight);
            Point fpt = new Point(halfOfWidth, quarterOfHeight);
            Point gpt = new Point(halfOfWidth + quarterOfHeight, halfOfHeight);
            Point hpt = new Point(this.ActualWidth - halfOfHeight, halfOfHeight);

            Point ipt = new Point(this.ActualWidth - quarterOfHeight, halfOfHeight);
            Point jpt = new Point(this.ActualWidth - quarterOfHeight, quarterOfHeight * 3);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                ctx.BeginFigure(apt, false /* is filled */, false /* is closed */);

                if (cpt.X > dpt.X || gpt.X > hpt.X)
                {
                    Point newB = new Point(bpt.X, bpt.Y - quarterOfHeight);
                    Point newE = new Point(ept.X, ept.Y + quarterOfHeight);
                    Point newI = new Point(ipt.X, ipt.Y - quarterOfHeight);
                    ctx.BezierTo(newB, newE, fpt, true, true);
                    ctx.BezierTo(newE, newI, jpt, true, true);
                }
                else
                {
                    ctx.QuadraticBezierTo(bpt, cpt, true, true);
                    ctx.LineTo(dpt, true, true);
                    ctx.QuadraticBezierTo(ept, fpt, true, true);
                    ctx.QuadraticBezierTo(ept, gpt, true, true);
                    ctx.LineTo(hpt, true, true);
                    ctx.QuadraticBezierTo(ipt, jpt, true, true);
                }
            }
        }

        private void DrawBottomBrace(StreamGeometry geometry, double halfOfWidth, double halfOfHeight, double quarterOfHeight)
        {
            Point apt = new Point(quarterOfHeight, quarterOfHeight);
            Point bpt = new Point(quarterOfHeight, halfOfHeight);
            Point cpt = new Point(halfOfHeight, halfOfHeight);
            Point dpt = new Point(halfOfWidth - quarterOfHeight, halfOfHeight);

            Point ept = new Point(halfOfWidth, halfOfHeight);//中心点

            Point fpt = new Point(halfOfWidth, quarterOfHeight * 3);
            Point gpt = new Point(halfOfWidth + quarterOfHeight, halfOfHeight);
            Point hpt = new Point(this.ActualWidth - halfOfHeight, halfOfHeight);

            Point ipt = new Point(this.ActualWidth - quarterOfHeight, halfOfHeight);
            Point jpt = new Point(this.ActualWidth - quarterOfHeight, quarterOfHeight);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                ctx.BeginFigure(apt, false /* is filled */, false /* is closed */);

                if (cpt.X > dpt.X || gpt.X > hpt.X)
                {
                    Point newB = new Point(bpt.X, bpt.Y + quarterOfHeight);
                    Point newE = new Point(ept.X, ept.Y - quarterOfHeight);
                    Point newI = new Point(ipt.X, ipt.Y + quarterOfHeight);
                    ctx.BezierTo(newB, newE, fpt, true, true);
                    ctx.BezierTo(newE, newI, jpt, true, true);
                }
                else
                {
                    ctx.QuadraticBezierTo(bpt, cpt, true, true);
                    ctx.LineTo(dpt, true, true);
                    ctx.QuadraticBezierTo(ept, fpt, true, true);
                    ctx.QuadraticBezierTo(ept, gpt, true, true);
                    ctx.LineTo(hpt, true, true);
                    ctx.QuadraticBezierTo(ipt, jpt, true, true);
                }
            }
        }
    }
}
